package graph;

import java.util.ArrayList;

import task_system.TaskSystem;
import exception.ImpossibleTaskConfigurationException;

public class GraphBackup {

	public int m;

	ArrayList<Node> failure_nodes_scheduler = new ArrayList<Node>();
	ArrayList<Node> failure_nodes_system = new ArrayList<Node>();

	ArrayList<Node> visited = new ArrayList<Node>();

	private TaskSystem taskSystem;

	public GraphBackup(TaskSystem ts) {
		taskSystem = ts;
	}

	public void calculate_bad_nodes(){
		try {
			int size = taskSystem.tasks().size();
			failureNodesSystem(0, size, new ArrayList<TaskConfiguration>());
			failureNodesScheduler(0, size, new ArrayList<TaskConfiguration>());
			System.out.println(failure_nodes_system.size() + " " + failure_nodes_scheduler.size());
			optimization();
			System.out.println(failure_nodes_system.size() + " " + failure_nodes_scheduler.size());
			System.out.println("done");
		} catch (ImpossibleTaskConfigurationException e) {
			System.out.println(e.message());
			e.printStackTrace();
		}
	}

	@SuppressWarnings("unchecked")
	private void failureNodesScheduler(int number, int size,
			ArrayList<TaskConfiguration> nodeConfig)
			throws ImpossibleTaskConfigurationException {
		for (int p = 0; p <= taskSystem.tasks().get(number).P(); p++) {
				int d = p - (taskSystem.tasks().get(number).P() - taskSystem.tasks().get(number).D());
				if (d < 0 )
					d=0;
				for (int c = 0; c <= taskSystem.tasks().get(number).C(); c++) {

					ArrayList<TaskConfiguration> nc = (ArrayList<TaskConfiguration>) nodeConfig
							.clone();
					if (!(((p - d) != (taskSystem.tasks().get(number).P() - taskSystem
							.tasks().get(number).D()) && d != 0)
							|| (d == 0 && p > (taskSystem.tasks().get(number)
									.P() - taskSystem.tasks().get(number).D()))
							|| p > taskSystem.tasks().get(number).P()
							|| d > taskSystem.tasks().get(number).D()
							|| c > taskSystem.tasks().get(number).C() || (c < taskSystem
							.tasks().get(number).C()
							&& p == taskSystem.tasks().get(number).P() && d == taskSystem
							.tasks().get(number).D()))) {
//					if(!taskSystem.tasks().get(number).notCompatibleConfiguration(p, d, c)){
//					if(taskSystem.tasks().get(number).compatibleConfiguration(p, d, c)){

						nc.add(new TaskConfiguration_Scheduler(p, d, c,
								taskSystem.tasks().get(number)));
					}
					if (number == size - 1) {
						if (nc.size() == size) {
							Node_Scheduler n = new Node_Scheduler(nc);
							if (n.failure()) {
								failure_nodes_scheduler.add(n);
							}
						}
					} else {
						failureNodesScheduler(number + 1, size, nc);
					}
				}
//			}
		}
	}

	@SuppressWarnings("unchecked")
	private void failureNodesSystem(int number, int size,
			ArrayList<TaskConfiguration> nodeConfig)
			throws ImpossibleTaskConfigurationException {
		
		for (int p = 0; p <= taskSystem.tasks().get(number).P(); p++) {
			int d = p - (taskSystem.tasks().get(number).P() - taskSystem.tasks().get(number).D());
			if (d < 0 )
				d=0;
				for (int c = 0; c <= taskSystem.tasks().get(number).C(); c++) {

					ArrayList<TaskConfiguration> nc = (ArrayList<TaskConfiguration>) nodeConfig
							.clone();
					if (!(((p - d) != (taskSystem.tasks().get(number).P() - taskSystem
							.tasks().get(number).D()) && d != 0)
							|| (d == 0 && p > (taskSystem.tasks().get(number)
									.P() - taskSystem.tasks().get(number).D()))
							|| p > taskSystem.tasks().get(number).P()
							|| d > taskSystem.tasks().get(number).D()
							|| c > taskSystem.tasks().get(number).C()
							|| (c < taskSystem.tasks().get(number).C()
									&& p == taskSystem.tasks().get(number).P() && d == taskSystem
									.tasks().get(number).D()) || (p == taskSystem
							.tasks().get(number).P() || d == taskSystem.tasks()
							.get(number).D()))) {
//					if(!taskSystem.tasks().get(number).notCompatibleConfiguration(p, d, c)){

						nc.add(new TaskConfiguration_System(p, d, c, taskSystem
								.tasks().get(number)));
					}
					if (number == size - 1) {
						if (nc.size() == size) {
							Node_System n = new Node_System(nc);
							if (n.failure()) {
								failure_nodes_system.add(n);
							}
						}
					} else {
						failureNodesSystem(number + 1, size, nc);
					}
				}
//			}
		}
	}

	public ArrayList<Node> failure_nodes_scheduler() {
		return failure_nodes_scheduler;
	}

	public ArrayList<Node> failure_nodes_system() {
		return failure_nodes_system;
	}
	
	private boolean is_in_failure_system(Node n){
		for(Node n_sys : failure_nodes_system){
			if (n_sys.equals(n)){
				return true;
			}
		}
		return false;
	}
	
	private boolean is_in_failure_scheduler(Node n){
		for(Node n_sch : failure_nodes_scheduler){
			if (n_sch.equals(n)){
				return true;
			}
		}
		return false;
	}
	
	public String toString(){
		String result = "";
				
		result += "\nSystem failure states \n\n";
		result += failure_nodes_system.size();
		for(Node n : failure_nodes_system){
			result += "System\n"+ n.toString() + "\n";
		}
		
		result += "Scheduler failure states\n\n";
		result += failure_nodes_scheduler.size();

		for(Node n : failure_nodes_scheduler){
			result += "Scheduler\n"+ n.toString() + "\n";
		}
		return result;
	}
	
	public Node_System initial_state(){
		ArrayList<TaskConfiguration> tcs = new ArrayList<TaskConfiguration>();

		for (int i=0; i < taskSystem.tasks().size(); i++){
			try {
				tcs.add(new TaskConfiguration_System(0,0,0,taskSystem.tasks().get(i)));

			} catch (ImpossibleTaskConfigurationException e) {
				e.printStackTrace();
			}
		}
		return new Node_System(tcs);
	}
	@SuppressWarnings("all")
	private void optimization(){
		ArrayList<Node> copy_system = (ArrayList<Node>)failure_nodes_system.clone();
		
		for(Node fs : copy_system){
			for(Node prec : fs.predecessors()){
				boolean all_predecessors_in_failure = true;
				if(!is_in_failure_scheduler(prec))
					all_predecessors_in_failure = false;
				if(all_predecessors_in_failure)
					failure_nodes_system.remove(fs);
			}
		}
		ArrayList<Node> copy_scheduler = (ArrayList<Node>)failure_nodes_scheduler.clone();

		for(Node fs : copy_scheduler){
			for(Node prec : fs.predecessors()){
				if(is_in_failure_system(prec)){
						failure_nodes_scheduler.remove(fs);
						break;
				}
			}
		}
	}
}

//package graph;
//
//import java.util.ArrayList;
//
//import task_system.TaskSystem;
//import exception.ImpossibleTaskConfigurationException;
//
//public class Graph {
//
//	public int m;
//
//	ArrayList<Node> failure_nodes_scheduler = new ArrayList<Node>();
//	ArrayList<Node> failure_nodes_system = new ArrayList<Node>();
//
//	ArrayList<Node> visited = new ArrayList<Node>();
//
//	private TaskSystem taskSystem;
//
//	public Graph(TaskSystem ts) {
//		taskSystem = ts;
//	}
//
//	public void calculate_bad_nodes(){
//		try {
//			int size = taskSystem.tasks().size();
//			failureNodesSystem(0, size, new ArrayList<TaskConfiguration>());
//			failureNodesScheduler(0, size, new ArrayList<TaskConfiguration>());
//			System.out.println(failure_nodes_system.size() + " " + failure_nodes_scheduler.size());
//			optimization();
//			System.out.println(failure_nodes_system.size() + " " + failure_nodes_scheduler.size());
//			System.out.println("done");
//		} catch (ImpossibleTaskConfigurationException e) {
//			System.out.println(e.message());
//			e.printStackTrace();
//		}
//	}
//
//	@SuppressWarnings("unchecked")
//	private void failureNodesScheduler(int number, int size,
//			ArrayList<TaskConfiguration> nodeConfig)
//			throws ImpossibleTaskConfigurationException {
//		
//		for (int p = taskSystem.tasks().get(number).P(); p >= 0 ; p--) {
//				int d = p - (taskSystem.tasks().get(number).P() - taskSystem.tasks().get(number).D());
//				if (d < 0 )
//					d=0;
//				boolean failure_found = false;
//				for (int c = taskSystem.tasks().get(number).C(); c >= 0 && failure_found == false; c--) {
//
//					ArrayList<TaskConfiguration> nc = (ArrayList<TaskConfiguration>) nodeConfig.clone();
////					if (!(((p - d) != (taskSystem.tasks().get(number).P() - taskSystem
////							.tasks().get(number).D()) && d != 0)
////							|| (d == 0 && p > (taskSystem.tasks().get(number)
////									.P() - taskSystem.tasks().get(number).D()))
////							|| p > taskSystem.tasks().get(number).P()
////							|| d > taskSystem.tasks().get(number).D()
////							|| c > taskSystem.tasks().get(number).C() || (c < taskSystem
////							.tasks().get(number).C()
////							&& p == taskSystem.tasks().get(number).P() && d == taskSystem
////							.tasks().get(number).D()))) {
//					if(taskSystem.tasks().get(number).compatibleConfiguration(p, d, c)){
//
////						nc.add(new TaskConfiguration_Scheduler(p, d, c,
////								taskSystem.tasks().get(number)));
//						TaskConfiguration_Scheduler t = new TaskConfiguration_Scheduler(p,d,c, taskSystem.tasks().get(number));
//						if (t.failure()){
//							failure_found = true;
////							
////							System.out.println(t.toString() + " " + taskSystem.tasks().get(number).toString() + '\n');
//						}
//						nc.add(t);
//					}
//					if (number == size - 1) {
//						if (nc.size() == size) {
//							Node_Scheduler n = new Node_Scheduler(nc);
//							if (n.failure()) {
//								failure_nodes_scheduler.add(n);
////								
////								System.out.println(n.toString() +'\n');
//							}
//						}
//					} else {
//						failureNodesScheduler(number + 1, size, nc);
//					}
//				}
////			}
//		}
//	}
//
//	@SuppressWarnings("unchecked")
//	private void failureNodesSystem(int number, int size,
//			ArrayList<TaskConfiguration> nodeConfig)
//			throws ImpossibleTaskConfigurationException {
//		
//		for (int p = taskSystem.tasks().get(number).P() - 1; p >= 0 ; p--) {
//			int d = p - (taskSystem.tasks().get(number).P() - taskSystem.tasks().get(number).D());
//			if (d < 0 )
//				d=0;
//			boolean failure_found = false;
//				for (int c = taskSystem.tasks().get(number).C(); c >= 0 && failure_found == false; c--) {
//
//					ArrayList<TaskConfiguration> nc = (ArrayList<TaskConfiguration>) nodeConfig.clone();
////					if (!(((p - d) != (taskSystem.tasks().get(number).P() - taskSystem
////							.tasks().get(number).D()) && d != 0)
////							|| (d == 0 && p > (taskSystem.tasks().get(number)
////									.P() - taskSystem.tasks().get(number).D()))
////							|| p > taskSystem.tasks().get(number).P()
////							|| d > taskSystem.tasks().get(number).D()
////							|| c > taskSystem.tasks().get(number).C()
////							|| (c < taskSystem.tasks().get(number).C()
////									&& p == taskSystem.tasks().get(number).P() && d == taskSystem
////									.tasks().get(number).D()) || (p == taskSystem
////							.tasks().get(number).P() || d == taskSystem.tasks()
////							.get(number).D()))) {
//
//					if(taskSystem.tasks().get(number).compatibleConfiguration(p, d, c) && taskSystem.tasks().get(number).compatibleTaskConfigurationSystem(p, d, c)){
////						nc.add(new TaskConfiguration_System(p, d, c, taskSystem
////								.tasks().get(number)));
//						TaskConfiguration_System t = new TaskConfiguration_System(p,d,c, taskSystem.tasks().get(number));
//						
//						if (t.failure())
//							failure_found = true;
//						
//						nc.add(t);
//					}
//					if (number == size - 1) {
//						if (nc.size() == size) {
//							Node_System n = new Node_System(nc);
//							if (n.failure()) {
//								failure_nodes_system.add(n);
//							}
//						}
//					} else {
//						failureNodesSystem(number + 1, size, nc);
//					}
//				}
////			}
//		}
//	}
//
//	public ArrayList<Node> failure_nodes_scheduler() {
//		return failure_nodes_scheduler;
//	}
//
//	public ArrayList<Node> failure_nodes_system() {
//		return failure_nodes_system;
//	}
//	
//	private boolean is_in_failure_system(Node n){
//		for(Node n_sys : failure_nodes_system){
//			if (n_sys.equals(n)){
//				return true;
//			}
//		}
//		return false;
//	}
//	
//	private boolean is_in_failure_scheduler(Node n){
//		for(Node n_sch : failure_nodes_scheduler){
//			if (n_sch.equals(n)){
//				return true;
//			}
//		}
//		return false;
//	}
//	
//	public String toString(){
//		String result = "";
//				
//		result += "\nSystem failure states \n\n";
//		result += failure_nodes_system.size();
//		for(Node n : failure_nodes_system){
//			result += "System\n"+ n.toString() + "\n";
//		}
//		
//		result += "Scheduler failure states\n\n";
//		result += failure_nodes_scheduler.size();
//
//		for(Node n : failure_nodes_scheduler){
//			result += "Scheduler\n"+ n.toString() + "\n";
//		}
//		return result;
//	}
//	
//	public Node_System initial_state(){
//		ArrayList<TaskConfiguration> tcs = new ArrayList<TaskConfiguration>();
//
//		for (int i=0; i < taskSystem.tasks().size(); i++){
//			try {
//				tcs.add(new TaskConfiguration_System(0,0,0,taskSystem.tasks().get(i)));
//
//			} catch (ImpossibleTaskConfigurationException e) {
//				e.printStackTrace();
//			}
//		}
//		return new Node_System(tcs);
//	}
//	
//	private void optimization(){
//		ArrayList<Node> copy_system = (ArrayList<Node>)failure_nodes_system.clone();
//		
//		for(Node fs : copy_system){
//			for(Node prec : fs.predecessors()){
//				boolean all_predecessors_in_failure = true;
//				if(!is_in_failure_scheduler(prec))
//					all_predecessors_in_failure = false;
//				if(all_predecessors_in_failure)
//					failure_nodes_system.remove(fs);
//			}
//		}
//		ArrayList<Node> copy_scheduler = (ArrayList<Node>)failure_nodes_scheduler.clone();
//
//		for(Node fs : copy_scheduler){
//			for(Node prec : fs.predecessors()){
//				if(is_in_failure_system(prec)){
//						failure_nodes_scheduler.remove(fs);
//						break;
//				}
//			}
//		}
//	}
//}

